# -*- coding: utf-8 -*--


import exceptions
import mur, porte, figurine



CASE_VIDE = " "
CASE_MUR    = "#"
CASE_PORTE = "-"
CASE_FIGURINE = "X"

HAUTEUR_MIN, LARGEUR_MIN = 10, 10
HAUTEUR_MAX, LARGEUR_MAX = 100, 100

VERTICAL, HORIZONTAL = 1000, 2000

class ErreurCarte( exceptions.Exception ):
    pass



class Carte:    
    "Classe Carte"    
    def __init__( self, i_hauteur, i_largeur ):   
        """Constructeur de la classe Carte
        __init__(i_hauteur:int, i_largeur:int)
        """        

        self.__i_hauteur = i_hauteur
        self.__i_largeur = i_largeur
        self.__figurines = list( )
        self.__a_murs    = list( )
        self.__a_portes  = list( )
        self.__verifCarte( )            


    def getHauteur( self ):
        """Retourne la hauteur de la carte
        getHauteur( ) -> int
        """
        return self.__i_hauteur
        
    def getLargeur( self ):
        """Retourne la largeur de la carte
        getLargeur( ) -> int
        """
        return self.__i_largeur

    def addFigurine( self, o_figurine ):
        if not isinstance( o_figurine, figurine.Figurine ):
            raise ErreurCarte( "Le paramètre doit être de type de Figurine" )
        for o_fig in self.__figurines:
            if o_fig.getPosition( ) == o_figurine.getPosition( ):
                raise ErreurCarte( "Une figurine se trouve déjà sur cette case" )            
        if o_figurine not in self.__figurines:
            self.__figurines.append( o_figurine )

    def countFigurines( self ):
        return len( self.__figurines )
        
    def getFigurines( self ):
        return self.__figurines

    def addMur( self, i_position_x, i_position_y, i_longueur, i_alignement ):
        entier = type( 1 )
        if type( i_position_x ) != entier or type( i_position_y ) != entier or type( i_longueur ) != entier or type( i_alignement ) != entier:
            raise ErreurCarte( "Les paramètres de la méthode addMur doivent être de type 'int'" )         
        if i_position_x < 0 or i_position_y < 0:
            raise ErreurCarte( "Le mur doit être sur la carte" )
        if i_alignement == VERTICAL and i_longueur > self.getHauteur( ):
            raise ErreurCarte( "Le mur ne doit pas être plus long que la hauteur de la carte" )
        elif i_alignement == HORIZONTAL and i_longueur > self.getLargeur( ):
            raise ErreurCarte( "Le mur ne doit pas être plus long que la largeur de la carte" )
        un_mur = mur.Mur( i_position_x, i_position_y, i_longueur, i_alignement )
        for case in un_mur.getCasesPrises( ):
            if self.hasElement( case[0], case[1] ):
                raise ErreurCarte( "Un élément est déjà présent sur cet emplacement" )
            if case[0] > self.getLargeur( ) - 1 or case[1] > self.getHauteur( ) - 1:
                raise ErreurCarte( "Toute la longeur du mur doit se trouver sur la carte" )
        self.__a_murs.append( un_mur )
    
    def hasMur( self, i_position_x, i_position_y ):
        entier = type( 1 )
        if type( i_position_x ) != entier or type( i_position_y ) != entier:
            raise ErreurCarte( "Les paramètres de la méthode hasMur doit être de type 'int'" )
        for o_mur in self.__a_murs:
            for t_position in o_mur.getCasesPrises(  ):
                if t_position == ( i_position_x, i_position_y ):
                    return True
        return False
    
    def addPorte( self, i_position_x, i_position_y, i_longueur, i_alignement ):
        entier = type( 1 )
        if type( i_position_x ) != entier or type( i_position_y ) != entier or type( i_longueur ) != entier or type( i_alignement ) != entier:
            raise ErreurCarte( "Les paramètres de la méthode addPorte doivent être de type 'int'" ) 
        if i_position_x < 0 or i_position_y < 0:
            raise ErreurCarte( "La porte doit être sur la carte" )
        if i_alignement == VERTICAL and i_longueur > self.getHauteur( ):
            raise ErreurCarte( "La porte ne doit pas être plus long que la hauteur de la carte" )
        elif i_alignement == HORIZONTAL and i_longueur > self.getLargeur( ):
            raise ErreurCarte( "La porte ne doit pas être plus long que la largeur de la carte" )
        une_porte = porte.Porte( i_position_x, i_position_y, i_longueur, i_alignement )
        for case in une_porte.getCasesPrises( ):
            if self.hasElement( case[0], case[1] ):
                raise ErreurCarte( "Un élément est déjà présent sur cet emplacement" )
            if case[0] > self.getLargeur( ) - 1 or case[1] > self.getHauteur( ) - 1:
                raise ErreurCarte( "Toute la longeur de la porte doit se trouver sur la carte" )
        self.__a_portes.append( une_porte )
        
    def hasPorte( self, i_position_x, i_position_y ):
        entier = type( 1 )
        if type( i_position_x ) != entier or type( i_position_y ) != entier:
            raise ErreurCarte( "Les paramètres de la méthode hasPorte doit être de type 'int'" )
        for o_porte in self.__a_portes:
            for t_position in o_porte.getCasesPrises(  ):
                if t_position == ( i_position_x, i_position_y ):
                    return True
        return False
    
    def hasFigurine( self, i_position_x, i_position_y ):
        entier = type( 1 )
        if type( i_position_x ) != entier or type( i_position_y ) != entier:
            raise ErreurCarte( "Les paramètres de la méthode hasFigurine doit être de type 'int'" )
        for o_figurine in self.getFigurines():
            if o_figurine.getPosition(  ) == ( i_position_x, i_position_y ):
                return True
        return False
    
    def hasElement( self, i_position_x, i_position_y ):
        return self.hasMur( i_position_x, i_position_y ) or self.hasPorte( i_position_x, i_position_y ) or self.hasFigurine( i_position_x, i_position_y )
    
    def __verifCarte( self ):
        entier = type( 1 ) 
        if type( self.__i_hauteur ) != entier or type( self.__i_largeur ) != entier:
            raise ErreurCarte( "Les paramètres du constructeur doivent être de type 'int'" )
        if self.__i_hauteur < HAUTEUR_MIN:
            raise ErreurCarte( "La largeur de la carte est trop petite" )
        if self.__i_largeur < LARGEUR_MIN:
            raise ErreurCarte( "La largeur de la carte est trop petite" )
        if self.__i_hauteur > HAUTEUR_MAX:
            raise ErreurCarte( "La hauteur de la carte est trop grande" )
        if self.__i_largeur > LARGEUR_MAX:
            raise ErreurCarte( "La largeur de la carte est trop grande" )

    
    def fabrique( self ):
        self.__carte = list( self.__i_hauteur * self.__i_largeur * CASE_VIDE ) 
        for o_mur in self.__a_murs:
           for case in o_mur.getCasesPrises( ):
               self.__carte[self.__pgcd( case[0], case[1] )] = CASE_MUR
        for o_porte in self.__a_portes:
           for case in o_porte.getCasesPrises( ):
               self.__carte[self.__pgcd( case[0], case[1] )] = CASE_PORTE
        for o_figurine in self.getFigurines() :
           case = o_figurine.getPosition( )
           self.__carte[self.__pgcd( case[0], case[1] )] = CASE_FIGURINE
           
    def getPerimetre( self ):
        l_perimetre = list () 
        for i in range (self.__i_hauteur):
            l_perimetre.append ( (0, i) )
            l_perimetre.append ( (self.__i_largeur - 1, i) )
        
        for i in range (1, self.__i_largeur - 1):
            l_perimetre.append ( (i, 0) )
            l_perimetre.append ( (i, self.__i_hauteur - 1) )
         
        return l_perimetre

    def __pgcd( self, x, y ):
        return self.__i_largeur * y + x
    
    def getPgcd(self, x, y ):
        return self.__pgcd( x, y )
    
    def __repr__( self ):
        self.fabrique( )
        s_sortie = "+" + ( "-" * (self.__i_largeur * 4 - 2) ) + "-+\n" 
        y = 0        
        for y in range( self.__i_hauteur ):
            s_sortie += "| "
            for x in range( self.__i_largeur ):
                s_sortie += self.__carte[self.__pgcd( x, y )] + " | "
            s_sortie += "\n"
            s_sortie += "+" + ( "-" * (self.__i_largeur * 4 - 2) ) + "-+\n"        
        return s_sorti